﻿using System;
using Present.Commands.Rx;

namespace Present.Commands.Async.Actions.Decorators
{
    /// <summary>
    /// Decorates a target with busy functionality
    /// The busyable item passed in will be busyed while the inner command is being executed
    /// </summary>
    /// <typeparam name="TParameter"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    public class BusyAsyncActionDecorator<TParameter, TResult> : AsyncActionDecorator<TParameter, TResult>
    {
        private readonly IBusyable busyable;

        public BusyAsyncActionDecorator(IAsyncAction<TParameter, TResult> innerTarget, IBusyable busyable) : base(innerTarget)
        {
            this.busyable = busyable;
            busyable.WhenPropertyChanges(b => b.IsBusy).Subscribe(x => RaiseCanExecuteChanged());
        }

        public override void HandleSuccess(TResult result)
        {
            try
            {
                base.HandleSuccess(result);
            }
            finally
            {
                EndBusy();
            }
           
        }

        public override ActionExecution<TParameter> PrepareWork(TParameter parameter)
        {
            BeginBusy();
            return base.PrepareWork(parameter);
        }

     
        public override void HandleError(Exception error)
        {
            EndBusy();
            base.HandleError(error);
        }

        public override bool CanExecute(object parameter)
        {
            return !busyable.IsBusy && base.CanExecute(parameter);
        }

        private void BeginBusy()
        {
            busyable.IsBusy = true;
        }

        private void EndBusy()
        {
            busyable.IsBusy = false;
        }
    }
}